<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>JavaScript Prettifier</title>
    <link rel="stylesheet" type="text/css" href="style.css" />
    <script type="text/javascript" src="astring.min.js"></script>
  </head>
  <body>
    <h1>JavaScript Prettifier</h1>
    <p>
      Parses the code with
      <a href="https://github.com/acornjs/acorn">Acorn</a> and prints it with
      <a href="https://github.com/davidbonnet/astring">Astring</a>.
    </p>
    <textarea
      id="console"
      rows="10"
      placeholder="Type your code here"
      spellcheck="false"
    ></textarea>
    <p class="settings">
      <label><input type="checkbox" id="comments" /> Include comments</label>
      <label
        ><input
          type="number"
          id="indentation"
          value="2"
          min="0"
          step="1"
          style="width: 3em"
        />
        Indentation spaces</label
      >
      <label><input type="checkbox" id="ast" /> Only show the AST</label>
      <button id="setlink">Set link</button>
    </p>
    <pre id="output"></pre>
    <script type="module">
      import * as astravel from 'https://cdn.skypack.dev/astravel'
      import * as acorn from 'https://cdn.skypack.dev/acorn'

      const document = window.document
      const textarea = document.getElementById('console')
      const pre = document.getElementById('output')
      const commentsCheckbox = document.getElementById('comments')
      const indentationTextbox = document.getElementById('indentation')
      const astCheckbox = document.getElementById('ast')
      const linkButton = document.getElementById('setlink')

      const ecmaVersion = 13

      function makeSpaces(amount) {
        var result = ''
        while (amount-- > 0) result += ' '
        return result
      }

      function replacer(key, value) {
        if (typeof value === 'bigint') {
          return undefined
        }
        return value
      }

      function update() {
        try {
          var indentAmount = parseInt(indentationTextbox.value)
          var indent = makeSpaces(indentAmount)
          if (commentsCheckbox.checked) {
            var comments = []
            var ast = acorn.parse(textarea.value, {
              ecmaVersion: ecmaVersion,
              sourceType: 'module',
              locations: true,
              onComment: comments,
            })
            astravel.attachComments(ast, comments)
            if (astCheckbox.checked) {
              pre.innerHTML = JSON.stringify(ast, replacer, indent)
              textarea.className = ''
              return
            }
            var formattedCode = astring.generate(ast, {
              indent: indent,
              comments: true,
            })
          } else {
            var ast = acorn.parse(textarea.value, {
              ecmaVersion: ecmaVersion,
              sourceType: 'module',
            })
            if (astCheckbox.checked) {
              pre.innerHTML = JSON.stringify(ast, replacer, indent)
              textarea.className = ''
              return
            }
            var formattedCode = astring.generate(ast, {
              indent: indent,
            })
          }
          pre.innerHTML = formattedCode
        } catch (error) {
          textarea.className = 'invalid'
          pre.innerHTML = error.toString() + '\n\n' + error.stack
          return
        }
        textarea.className = ''
      }

      function onHashChange() {
        var code = window.location.hash.substr(1)
        textarea.value = decodeURI(code)
        update()
      }
      window.addEventListener('hashchange', onHashChange, false)

      function setLink() {
        window.location.hash = '#' + encodeURI(textarea.value)
      }

      linkButton.addEventListener('click', setLink, false)
      textarea.addEventListener('input', update, false)
      commentsCheckbox.addEventListener('change', update, false)
      indentationTextbox.addEventListener('change', update, false)
      astCheckbox.addEventListener('change', update, false)

      onHashChange()
    </script>
  </body>
</html>
